<!DOCTYPE html>
<html>
  <head>
     
    <meta charset="UTF-8">
    <title>MySQL2 - 测开、Java后端最常见、最核心的面试题总结</title>
    <link rel="shortcut icon" href="/static/img/icon.png">
    <link rel="icon" href="/static/img/icon.png" sizes="192x192"/>
    
<link rel="stylesheet" href="/static/kico.css">
<link rel="stylesheet" href="/static/hingle.css">

    
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

    <meta name="viewport" content="width=device-width, maximum-scale=1, initial-scale=1"/>
    <meta property="og:site_name" content="测开、Java后端最常见、最核心的面试题总结">
    <meta property="og:title" content="MySQL2"/>
    
<meta name="generator" content="Hexo 7.3.0"></head>

  <body>
    <header>
    <div class="head-title">
        <h4>测开、Java后端最常见、最核心的面试题总结</h4>
    </div>
    <div class="head-action">
        <div class="toggle-btn"></div>
        <div class="light-btn"></div>
        <div class="search-btn"></div>
    </div>
    <form class="head-search" method="post">
        <input type="text" name="s" placeholder="搜索什么？">
    </form>
    <nav class="head-menu">
        <a href="/">首页</a>
        
    </nav>
</header>

    <main>
    <div class="wrap min">
        <section class="post-title">
            <h2>MySQL2</h2>
            <div class="post-meta">
                <time class="date">2024.07.31</time>
            
            </div>
        </section>
        <article class="post-content">
        
            <h1><span id="19慢-sql-如何定位">19.慢 SQL 如何定位？</span></h1><p>顾名思义，慢 SQL 也就是执行时间较长的 SQL 语句，MySQL 中 long_query_time 默认值是 10 秒，也就是执行时间超过 10 秒的 SQL 语句会被记录到慢查询日志中。可通过 <code>show variables like &#39;long_query_time&#39;;</code> 查看当前的 long_query_time 值。不过，生产环境中，10 秒太久了，超过 1 秒的都可以认为是慢 SQL 了。</p>
<p><strong>那怎么定位慢 SQL 呢？</strong></p>
<ol>
<li>启用慢查询日志</li>
<li>设置慢查询时间阈值</li>
<li>分析慢查询日志</li>
</ol>
<ul>
<li>直接查看日志文件：<br>  可以使用文本编辑器查看和分析。</li>
<li>使用 <code>mysqldumpslow</code> 工具：<br>  MySQL 提供了一个名为 <code>mysqldumpslow</code> 的工具来汇总慢查询日志的内容。它可以按不同的方式对查询进行排序，比如按执行次数、平均时间、总时间等。</li>
</ul>
<ol start="4">
<li>使用 <code>EXPLAIN</code> 分析慢 SQL<br>一旦定位到某个慢 SQL，可以使用 <code>EXPLAIN</code> 命令来分析查询的执行计划，以确定哪些部分可能导致了性能问题。<code>EXPLAIN</code> 会返回查询的执行计划，包括使用了哪些索引、数据扫描量、执行顺序等信息，这有助于识别查询的瓶颈。</li>
<li>优化查询和索引<br>根据 <code>EXPLAIN</code> 的结果以及慢查询的具体情况，可以尝试通过以下方式来优化查询：</li>
</ol>
<ul>
<li><strong>添加或优化索引</strong></li>
<li><strong>优化查询语句</strong></li>
<li><strong>调整数据库表结构</strong></li>
<li><strong>使用缓存机制</strong></li>
</ul>
<h1><span id="20有哪些方式优化-sql">20.有哪些方式优化 SQL？</span></h1><p><strong>避免不必要的列：</strong><br>比如说尽量避免使用 <code>select *</code>，只查询需要的列，减少数据传输量。</p>
<p><strong>分页优化：</strong><br>当数据量巨大时，传统的<code>LIMIT</code>和<code>OFFSET</code>可能会导致性能问题，因为数据库需要扫描<code>OFFSET + LIMIT</code>数量的行。<br>一般分页查询时，通过创建覆盖索引和子查询的形式能够比较好地提高性能。</p>
<p><strong>排序优化：</strong><br>MySQL 生成有序结果的方式有两种：一种是对结果集进行排序操作，另外一种是按照索引顺序扫描得出的自然有序结果。<br>因此在设计索引的时候要充分考虑到排序的需求。<br><code>select id, name from users order by name;</code><br>如果 name 字段上有索引，那么 MySQL 可以直接利用索引的有序性，避免排序操作。</p>
<p><strong>索引优化：</strong></p>
<p><strong>①、利用覆盖索引</strong><br>使用非主键索引查询数据时需要回表，但如果索引的叶节点中已经包含要查询的字段，那就不会再回表查询了，这就叫覆盖索引。</p>
<p><strong>②、避免使用 !&#x3D; 或者 &lt;&gt; 操作符</strong><br><code>!=</code> 或者 <code>&lt;&gt;</code> 操作符会导致 MySQL 无法使用索引，从而导致全表扫描。<br>例如，可以把<code>column&lt;&gt;&#39;aaa&#39;</code>，改成<code>column&gt;&#39;aaa&#39; or column&lt;&#39;aaa&#39;</code>，就可以使用索引了。<br>优化策略就是尽可能使用 <code>=</code>、<code>&gt;</code>、<code>&lt;</code>、<code>BETWEEN</code>等操作符，它们能够更好地利用索引。</p>
<p><strong>③、适当使用前缀索引</strong><br>适当使用前缀索引可以降低索引的空间占用，提高索引的查询效率。<br>比如，邮箱的后缀一般都是固定的<code>@xxx.com</code>，那么类似这种后面几位为固定值的字段就非常适合定义为前缀索引：<br>需要注意的是，MySQL 无法利用前缀索引做 order by 和 group by 操作。</p>
<p><strong>④、避免索引列上使用函数</strong><br>在 where 子句中直接对索引列使用函数会导致索引失效，因为数据库需要对每行的列应用函数后再进行比较，无法直接利用索引。</p>
<p><strong>⑤、正确使用联合索引</strong><br>正确地使用联合索引可以极大地提高查询性能，联合索引的创建应遵循最左前缀原则，即索引的顺序应根据列在查询中的使用频率和重要性来安排。</p>
<p><strong>JOIN 优化：</strong><br>对于 JOIN 操作，可以通过优化子查询、小表驱动大表、适当增加冗余字段、避免 join 太多表等方式来进行优化。</p>
<p><strong>①、优化子查询</strong><br>子查询，特别是在 select 列表和 where 子句中的子查询，往往会导致性能问题，因为它们可能会为每一行外层查询执行一次子查询。<br>使用子查询：<code>select name from A where id in (select id from B);</code><br>使用 JOIN 代替子查询：<code>select A.name from A join B on A.id=B.id;</code></p>
<p><strong>②、小表驱动大表</strong><br>在执行 JOIN 操作时，应尽量让行数较少的表（小表）驱动行数较多的表（大表），这样可以减少查询过程中需要处理的数据量。<br>当使用 <code>LEFT JOIN</code> 时，左表是驱动表，所以最好选择行数较少的表作为左表。这样可以减少需要处理的连接次数，进而加快查询速度。</p>
<p><strong>③、适当增加冗余字段</strong><br>在某些情况下，通过在表中适当增加冗余字段来避免 JOIN 操作，可以提高查询效率，尤其是在高频查询的场景下。</p>
<p><strong>④、避免使用 JOIN 关联太多的表</strong><br>因为 join 太多表会降低查询的速度，返回的数据量也会变得非常大，不利于后续的处理。<br>如果业务逻辑允许，可以考虑将复杂的 JOIN 查询分解成多个简单查询，然后在应用层组合这些查询的结果。</p>
<h1><span id="21explain执行计划各个字段的含义">21.explain执行计划，各个字段的含义？</span></h1><p>explain 是 MySQL 提供的一个用于查看查询执行计划的工具，可以帮助我们分析查询语句的性能瓶颈，找出慢 SQL 的原因。</p>
<p>使用方式也非常简单，在 select 语句前加上 <code>explain</code> 关键字就可以了。</p>
<p><strong>explain 输出结果中各个字段的含义：</strong></p>
<p>①、<strong>id</strong> 列：查询的标识符。</p>
<p>②、<strong>select_type</strong> 列：查询的类型。常见的类型有：</p>
<ul>
<li>SIMPLE：简单查询，不包含子查询或者 UNION 查询。</li>
<li>PRIMARY：查询中如果包含子查询，则最外层查询被标记为 PRIMARY。</li>
<li>SUBQUERY：子查询。</li>
<li>DERIVED：派生表的 SELECT，FROM 子句的子查询。</li>
</ul>
<p>③、<strong>table</strong> 列：查的哪个表。</p>
<p>④、<strong>type</strong> 列：表示连接类型或访问类型，显示 MySQL 访问表的方式。性能从最优到最差分别为：system &gt; const &gt; eq_ref &gt; ref &gt; range &gt; index &gt; ALL。</p>
<ul>
<li><code>system</code>：系统表（只有一行记录的表）。</li>
<li><code>const</code>：常量表（通过常量条件唯一找到一行数据）。</li>
<li><code>eq_ref</code>：唯一索引或主键索引（每次只能找到一行数据）。</li>
<li><code>ref</code>：非唯一索引（可以匹配多行）。</li>
<li><code>range</code>：范围扫描（索引范围查找）。</li>
<li><code>index</code>：全索引扫描（扫描整个索引）。</li>
<li><code>all</code>：全表扫描（扫描整个表）。</li>
</ul>
<p>⑤、<strong>possible_keys</strong> 列：可能会用到的索引，但并不一定实际被使用。</p>
<p>⑥、<strong>key</strong> 列：实际使用的索引。</p>
<p>⑦、<strong>key_len</strong> 列：表示使用的索引的长度，单位是字节。</p>
<p>⑧、<strong>ref</strong> 列：表示查询执行时用于查找匹配行的列或常量。通常用来显示索引的哪一部分被用于查找。</p>
<p>⑨、<strong>rows</strong> 列：估算查到结果集需要扫描的数据行数，原则上 rows 越少越好。</p>
<p>⑩、<strong>Extra</strong> 列：附加信息。</p>
<ul>
<li><code>Using index</code>：表示只利用了索引。</li>
<li><code>Using where</code>：表示使用了 WHERE 过滤。</li>
<li><code>Using filesort</code>：使用额外的排序操作。</li>
<li><code>Using temporary </code>：表示使用了临时表来存储中间结果。</li>
</ul>
<h1><span id="22能简单说一下索引的分类吗">22.能简单说一下索引的分类吗？</span></h1><p>MySQL 的索引可以显著提高查询的性能，可以从三个不同的维度对索引进行分类（功能、数据结构、存储位置）：</p>
<p><strong>从功能上的分类：</strong></p>
<p>①、主键索引: 表中每行数据唯一标识的索引，强调列值的唯一性和非空性。</p>
<p>②、唯一索引: 保证数据列中每行数据的唯一性，但允许有空值。</p>
<p>③、普通索引: 基本的索引类型，用于加速查询。</p>
<p>④、全文索引：特定于文本数据的索引，用于提高文本搜索的效率。</p>
<p><strong>从数据结构上分类：</strong></p>
<p>①、B+树索引：最常见的索引类型，一种将索引值按照一定的算法，存入一个树形的数据结构中（二叉树），每次查询都从树的根节点开始，一次遍历叶子节点，找到对应的值。查询效率是 O(logN)。也是 InnoDB 和 MyISAM 存储引擎的默认索引类型。</p>
<p>②、Hash 索引：基于哈希表的索引，查询效率可以达到 O(1)，但是只适合 &#x3D; 和 in 查询，不适合范围查询。是 MEMORY 存储引擎的默认索引类型。</p>
<p><strong>从数据和索引的组织结构上分类：</strong></p>
<p>①、聚簇索引：聚簇索引的叶子节点保存了一行记录的所有列信息。也就是说，聚簇索引的叶子节点中，包含了一个完整的记录行。</p>
<p>②、非聚簇索引：它的叶子节点只包含一个主键值，通过非聚簇索引查找记录要先找到主键，然后通过主键再到聚簇索引中找到对应的记录行，这个过程被称为回表。</p>
<p><strong>MySQL创建索引的方法</strong>：</p>
<ul>
<li>在创建表的定义语句 <code>CREATE TABLE</code> 中指定索引列，</li>
<li>使用<code>ALTER TABLE</code> 语句在存在的表上创建索引</li>
<li>使用<code>CREATE INDEX</code> 语句在已存在的表上添加索引。</li>
</ul>
<h1><span id="23索引哪些情况下会失效呢">23.索引哪些情况下会失效呢？</span></h1><ul>
<li><p>联合索引不满足最左前缀原则时，索引会失效。</p>
</li>
<li><p>在索引列上使用函数或表达式：如果在查询中对索引列使用了函数或表达式，那么索引可能无法使用，因为数据库无法预先计算出函数或表达式的结果。</p>
</li>
<li><p>使用不等于 (!&#x3D; 或 &lt;&gt;) 、IS NULL 或 IS NOT NULL操作符</p>
</li>
<li><p>使用 前缀模糊查询：如果 LIKE 的模式串是以“%”或者“_”开头的，那么索引也无法使用。</p>
</li>
<li><p>OR 操作符：如果查询条件中使用了 OR，并且 OR 两边的条件分别涉及不同的索引，那么这些索引可能都无法使用。</p>
</li>
<li><p>如果 MySQL 估计使用全表扫描比使用索引更快时（通常是小表或者大部分行都满足 WHERE 子句），也不会使用索引。</p>
</li>
</ul>
<h1><span id="24为什么-innodb-要使用-b树作为索引">24.为什么 InnoDB 要使用 B+树作为索引？</span></h1><p>MySQL 的默认存储引擎是 InnoDB，它采用的是 B+树索引，B+树是一种自平衡的多路查找树，和红黑树、二叉平衡树不同，B+树的每个节点可以有多个个子节点，而红黑树和二叉平衡树都只有 2 个。</p>
<p>和 B 树不同，B+树的非叶子节点只存储键值，不存储数据，而叶子节点存储了所有的数据，并且构成了一个有序链表。</p>
<p>这样做的好处是，非叶子节点上由于没有存储数据，就可以存储更多的键值对，再加上叶子节点构成了一个有序链表，范围查询时就可以直接通过叶子节点间的指针顺序访问整个查询范围内的所有记录，而无需对树进行多次遍历。查询的效率会更高。</p>
<h1><span id="25什么是回表">25.什么是回表？</span></h1><p>回表是指在数据库查询过程中，通过非聚簇索引查找到记录的主键值后，再根据这个主键值到聚簇索引中查找完整记录的过程。</p>
<p>回表操作通常发生在使用非聚簇索引进行查询，但查询的字段不全在该索引中，必须通过主键进行再次查询以获取完整数据。</p>
<p>换句话说，数据库需要先查找索引，然后再根据索引回到数据表中去查找实际的数据。</p>
<p>因此，使用非聚簇索引查找数据通常比使用聚簇索引要慢，因为需要进行两次磁盘访问。</p>
<h1><span id="26什么是覆盖索引">26.什么是覆盖索引？</span></h1><p>覆盖索引是指一个索引包含了查询所需的所有字段，因此不需要再去访问表中的数据行，可以直接从索引中获取所需的数据。这种情况可以显著提高查询性能，因为此时只需访问索引，而不需要进行回表操作。</p>
<h1><span id="27什么是最左前缀原则">27.什么是最左前缀原则？</span></h1><p>最左匹配原则是指在使用联合索引（即包含多列的索引）时，查询条件从索引的最左列开始并且不跳过中间的列。</p>
<p>如果一个复合索引包含<code>(col1, col2, col3)</code>，那么它可以支持 <code>col1</code>、<code>col1,col2</code> 和 <code>col1, col2, col3</code> 的查询优化，但不会优化只有 col2 或 col3 的查询。也就说，在进行查询时，如果没有遵循最左前缀，那么索引可能不会被利用，导致查询效率降低。</p>
<h1><span id="28mysql-中有哪几种锁列举一下">28.MySQL 中有哪几种锁，列举一下？</span></h1><p><strong>按锁粒度划分的话，MySQL 的锁有：</strong></p>
<ul>
<li>行级锁是mysql中锁定粒度最细的一种锁。表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突，其加锁粒度最小，但加锁的开销也最大。行级锁的类型主要有三类： Record Lock，记录锁，也就是仅仅把一条记录锁上；Gap Lock，间隙锁，锁定一个范围，但是不包含记录本身；Next-Key Lock，临键锁，Record Lock + Gap Lock 的组合，锁定一个范围，并且锁定记录本身。</li>
<li>表级锁是表示对当前操作的整张表加锁，它实现简单，资源消耗较少，被大部分mysql引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。</li>
<li>页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快，但冲突多，行级冲突少，但速度慢。因此，采取了折衷的页级锁，一次锁定相邻的一组记录。</li>
</ul>
<p><strong>按兼容性划分的话，MySQL 的锁有：</strong></p>
<ul>
<li>共享锁（S Lock）,也叫读锁（read lock），相互不阻塞。</li>
<li>排他锁（X Lock），也叫写锁（write lock），排它锁是阻塞的，在一定时间内，只有一个请求能执行写入，并阻止其它锁读取正在写入的数据。</li>
</ul>
<p><strong>按加锁机制如何划分?</strong></p>
<ul>
<li><p>乐观锁：乐观锁基于这样的假设：冲突在系统中出现的频率较低，因此在数据库事务执行过程中，不会频繁地去锁定资源。相反，它在提交更新的时候才检查是否有其他事务已经修改了数据。<br>可以通过在数据表中使用版本号（Version）或时间戳（Timestamp）来实现，每次读取记录时，同时获取版本号或时间戳，更新时检查版本号或时间戳是否发生变化。如果没有变化，则执行更新并增加版本号或更新时间戳；如果检测到冲突（即版本号或时间戳与之前读取的不同），则拒绝更新。</p>
</li>
<li><p>悲观锁：悲观锁假设冲突是常见的，因此在数据处理过程中，它会主动锁定数据，防止其他事务进行修改。<br>可以直接使用数据库的锁机制，如行锁或表锁，来锁定被访问的数据。常见的实现是 <code>SELECT FOR UPDATE</code> 语句，它在读取数据时就加上了锁，直到当前事务提交或回滚后才释放。</p>
</li>
</ul>
<h1><span id="29innodb-有哪几类行锁">29.InnoDB 有哪几类行锁？</span></h1><p>InnoDB 行锁是通过对索引数据页上的记录加锁实现的，MySQL InnoDB 支持三种行锁定方式：</p>
<ul>
<li><strong>记录锁（Record Lock）</strong>：也被称为记录锁，属于单个行记录上的锁。</li>
<li><strong>间隙锁（Gap Lock）</strong>：锁定一个范围，不包括记录本身。</li>
<li><strong>临键锁（Next-Key Lock）</strong>：Record Lock+Gap Lock，锁定一个范围，包含记录本身，主要目的是为了解决幻读问题。记录锁只能锁住已经存在的记录，为了避免插入新记录，需要依赖间隙锁。</li>
</ul>
<h1><span id="30意向锁有什么作用">30.意向锁有什么作用？</span></h1><p>如果需要用到表锁的话，如何判断表中的记录没有行锁呢，一行一行遍历肯定是不行，性能太差。我们需要用意向锁快速判断是否可以对某个表使用表锁。</p>
<p>意向锁是表级锁，共有两种：</p>
<ul>
<li><strong>意向共享锁（Intention Shared Lock，IS 锁）</strong>：事务有意向对表中的某些记录加共享锁（S 锁），加共享锁前必须先取得该表的 IS 锁。</li>
<li><strong>意向排他锁（Intention Exclusive Lock，IX 锁）</strong>：事务有意向对表中的某些记录加排他锁（X 锁），加排他锁之前必须先取得该表的 IX 锁。</li>
</ul>
<p><strong>意向锁是由数据引擎自己维护的，用户无法手动操作意向锁，在为数据行加共享&#x2F;排他锁之前，InooDB 会先获取该数据行所在在数据表的对应意向锁。</strong></p>
<h1><span id="31并发事务的控制方式有哪些">31.并发事务的控制方式有哪些？</span></h1><p>MySQL 中并发事务的控制方式主要有两种：<strong>锁</strong> 和 <strong>MVCC</strong>。锁可以看作是悲观控制的模式，多版本并发控制（MVCC，Multiversion concurrency control）可以看作是乐观控制的模式。</p>
<p><strong>锁</strong> 控制方式下会通过锁来显式控制共享资源而不是通过调度手段，MySQL 中主要是通过 <strong>读写锁</strong> 来实现并发控制。</p>
<ul>
<li><strong>共享锁（S 锁）</strong>：又称读锁，事务在读取记录的时候获取共享锁，允许多个事务同时获取（锁兼容）。</li>
<li><strong>排他锁（X 锁）</strong>：又称写锁&#x2F;独占锁，事务在修改记录的时候获取排他锁，不允许多个事务同时获取。如果一个记录已经被加了排他锁，那其他事务不能再对这条记录加任何类型的锁（锁不兼容）。</li>
</ul>
<p>读写锁可以做到读和读并行，但是无法做到读和写、写和写并行。另外，根据根据锁粒度的不同，又被分为 <strong>表级锁(table-level locking)</strong> 和 <strong>行级锁(row-level locking)</strong> 。InnoDB 不光支持表级锁，还支持行级锁，默认为行级锁。行级锁的粒度更小，仅对相关的记录上锁即可（对一行或者多行记录加锁），所以对于并发写入操作来说， InnoDB 的性能更高。不论是表级锁还是行级锁，都存在共享锁（Share Lock，S 锁）和排他锁（Exclusive Lock，X 锁）这两类。</p>
<p><strong>MVCC</strong> 是多版本并发控制方法，即对一份数据会存储多个版本，具体事务能看到哪个版本取决于事务的隔离级别和版本控制机制。。通常会有一个全局的版本分配器来为每一行数据设置版本号，版本号是唯一的。</p>
<p>MVCC 在 MySQL 中实现所依赖的手段主要是: <strong>隐藏字段、read view、undo log</strong>。</p>
<ul>
<li><strong>隐藏字段</strong>：在InnoDB存储引擎中，每行数据都包含一些隐藏的列，这些列用于存储数据的额外信息，比如行的创建时间戳和删除时间戳。这些时间戳帮助数据库跟踪数据的历史版本。</li>
<li><strong>Read View</strong>：Read View 是一种用于实现MVCC的数据结构，它是一个快照，记录了事务开始时数据库的状态。当一个事务读取数据时，它看到的是事务开始时的数据状态，而不是其他并发事务所做的更改。这样，即使其他事务在读取过程中修改了数据，当前事务也看不到这些更改，从而保证了数据的一致性。</li>
<li><strong>Undo Log</strong>：Undo Log 是一种日志，用于记录数据的变更历史。当事务进行修改操作时，Undo Log 会记录这些变更的逆操作。如果事务需要回滚，Undo Log 可以用来恢复数据到事务开始前的状态。同时，Undo Log 也支持MVCC，因为它可以保留数据的历史版本，使得其他事务可以看到数据的旧版本。</li>
</ul>
<h1><span id="32mysql-事务的四大特性说一下">32.MySQL 事务的四大特性说一下？</span></h1><p><strong>原子性</strong>（<code>Atomicity</code>）：事务是最小的执行单位，不允许分割。事务的原子性确保动作要么全部完成，要么完全不起作用；</p>
<p><strong>一致性</strong>（<code>Consistency</code>）：执行事务前后，数据保持一致，例如转账业务中，无论事务是否成功，转账者和收款人的总额应该是不变的；</p>
<p><strong>隔离性</strong>（<code>Isolation</code>）：并发访问数据库时，一个用户的事务不被其他事务所干扰，各并发事务之间数据库是独立的；</p>
<p><strong>持久性</strong>（<code>Durability</code>）：一个事务被提交之后。它对数据库中数据的改变是持久的，即使数据库发生故障也不应该对其有任何影响。</p>
<h1><span id="33那-acid-靠什么保证的呢">33.那 ACID 靠什么保证的呢？</span></h1><p>MySQL 通过事务、undo log、redo log 来确保 ACID。</p>
<p><strong>如何保证原子性？</strong></p>
<p>MySQL 通过 undo log 来确保原子性。当事务开始时，MySQL 会在<code>undo log</code>中记录事务开始前的旧值。如果事务执行失败，MySQL 会使用<code>undo log</code>中的旧值来回滚事务开始前的状态；如果事务执行成功，MySQL 会在某个时间节点将<code>undo log</code>删除。</p>
<p><strong>如何保证一致性？</strong></p>
<p>如果其他三个特性都得到了保证，那么一致性就自然而然得到保证了。</p>
<p><strong>如何保证隔离性？</strong></p>
<ul>
<li>锁机制：MySQL 使用行级锁、表级锁、意向锁等来控制事务之间的并发操作，确保数据的隔离性。</li>
<li>MVCC：MySQL 定义了多种隔离级别，通过 MVCC 来确保每个事务都有专属自己的数据版本，从而实现隔离性。在 MVCC 中，每行记录都有一个版本号，当事务尝试读取记录时，会根据事务的隔离级别和记录的版本号来决定是否可以读取。</li>
</ul>
<p><strong>如何保证持久性？</strong></p>
<p>redo log 是一种物理日志，当执行写操作时，MySQL 会先将更改记录到 redo log 中。当 redo log 填满时，MySQL 再将这些更改写入数据文件中。如果 MySQL 在写入数据文件时发生崩溃，可以通过 redo log 来恢复数据文件，从而确保持久性。</p>
<h1><span id="34并发事务带来了哪些问题">34.并发事务带来了哪些问题?</span></h1><p><strong>脏读</strong></p>
<p>一个事务读取数据并且对数据进行了修改，这个修改对其他事务来说是可见的，即使当前事务没有提交。这时另外一个事务读取了这个还未提交的数据，但第一个事务突然回滚，导致数据并没有被提交到数据库，那第二个事务读取到的就是脏数据，这也就是脏读的由来。</p>
<p><strong>不可重复读</strong></p>
<p>指在一个事务内多次读同一数据。在这个事务还没有结束时，另一个事务也访问该数据。那么，在第一个事务中的两次读数据之间，由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况，因此称为不可重复读。</p>
<p><strong>幻读</strong></p>
<p>幻读与不可重复读类似。它发生在一个事务读取了几行数据，接着另一个并发事务插入了一些数据时。在随后的查询中，第一个事务就会发现多了一些原本不存在的记录，就好像发生了幻觉一样，所以称为幻读。</p>

        </article>
        <section class="post-near">
            <ul>
                
                    <li>上一篇: <a href="/%E9%A1%B9%E7%9B%AE/">项目</a></li>
                
                
                    <li>下一篇: <a href="/Java17%E6%96%B0%E7%89%B9%E6%80%A7/">Java17新特性</a></li>
                
            </ul>
        </section>
        
    
        <section class="post-author">
        
            <figure class="author-avatar">
                <img src="https://sdn.geekzu.org/avatar/d22eb460ecab37fcd7205e6a3c55c228?s=200&r=X&d=" alt="Hingle" />
            </figure>
        
            <div class="author-info">
                <h4>Hingle</h4>
                <p>请在这里设置你的作者信息</p>
            </div>
        </section>
    
    </div>
</main>

    <footer>
    <div class="buttons">
        <a class="to-top" href="#"></a>
    </div>
    <div class="wrap min">
        <section class="widget">
            <div class="row">
                <div class="col-m-4">
                    <h3 class="title-recent">最新文章：</h3>
                    <ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/%E9%A1%B9%E7%9B%AE/">项目</a></li><li class="post-list-item"><a class="post-list-link" href="/MySQL2/">MySQL2</a></li><li class="post-list-item"><a class="post-list-link" href="/Java17%E6%96%B0%E7%89%B9%E6%80%A7/">Java17新特性</a></li><li class="post-list-item"><a class="post-list-link" href="/Redis2/">Redis2</a></li><li class="post-list-item"><a class="post-list-link" href="/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C2/">计算机网络2</a></li><li class="post-list-item"><a class="post-list-link" href="/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F2/">操作系统2</a></li></ul>
                </div>
            </div>
        </section>
        <section class="sub-footer">
            <p>© 2024 <a href="/">测开、Java后端最常见、最核心的面试题总结</a>. All Rights Reserved. Theme By <a href="https://github.com/Dreamer-Paul/Hingle" target="_blank" rel="nofollow">Hingle</a>.</p>
        </section>
    </div>
</footer>


<script src="/static/kico.js"></script>
<script src="/static/hingle.js"></script>


<script>var hingle = new Paul_Hingle({"copyright":false,"night":false});</script>

  </body>
</html>
